package operate_record

import (
	"context"
	"encoding/json"
	"fmt"
	"gozero-demo/internal/repo/es/es_constants"
	"gozero-demo/internal/svc"
	"gozero-demo/internal/utils"
	"time"

	"github.com/olivere/elastic/v7"
	"github.com/zeromicro/go-zero/core/logx"
)

const (
	OperateRecordTypeAdd    = 1 //新增
	OperateRecordTypeModify = 2 //修改
	OperateRecordTypeDelete = 3 //删除
)

type OperateRecordESRepository struct {
	logx.Logger
	ctx      context.Context
	esClient *elastic.Client
}

func NewOperateRecordESRepository(ctx context.Context, svcCtx *svc.ServiceContext) *OperateRecordESRepository {
	return &OperateRecordESRepository{
		Logger:   logx.WithContext(ctx),
		ctx:      ctx,
		esClient: svcCtx.ES,
	}
}

type OperateRecordESDocument struct {
	ID                 int64                  `json:"id"`
	BusinessTypeFirst  int64                  `json:"business_type_first"`  //业务类别第一级
	BusinessTypeSecond int64                  `json:"business_type_second"` //业务类别第二级
	OperateTable       string                 `json:"operate_table"`        //操作的数据表
	OperateTableId     int64                  `json:"operate_table_id"`     //操作的数据表ID
	BeforeData         string                 `json:"before_data"`          //变更前数据
	AfterData          string                 `json:"after_data"`           //变更后数据
	OperateType        int64                  `json:"operate_type"`         //操作类型 1:新增 2:修改 3:删除
	ChangedData        []OperateRecordChanged `json:"changed_data"`         //变更的数据的结构体
	CreateStaffId      int64                  `json:"create_staff_id"`      //创建人ID
	CreateTime         string                 `json:"create_time"`          //创建时间
}

// OperateRecordChanged 变更数据结构体
type OperateRecordChanged struct {
	Action      string `json:"action"`       //操作行为
	FieldName   string `json:"field_name"`   //字段名称
	BeforeValue string `json:"before_value"` //变更前的值
	AfterValue  string `json:"after_value"`  //变更后的值
}

func (r *OperateRecordESRepository) InsertEsData(doc *OperateRecordESDocument) error {
	if doc.ID == 0 {
		// 设置当前时间的毫秒级时间戳作为 ID
		doc.ID = time.Now().UnixNano() / int64(time.Millisecond)
	}
	fmt.Println("doc: ", utils.EchoJson(doc))

	// 创建文档
	_, err := r.esClient.Index().
		Index(es_constants.EsIndexOperateRecord).
		BodyJson(doc).
		Id(fmt.Sprintf("%d", doc.ID)).
		Do(r.ctx)
	if err != nil {
		return err
	}
	return nil
}

func (r *OperateRecordESRepository) InsertEsDataBatch(docList []*OperateRecordESDocument) error {
	req := r.esClient.Bulk().Index(es_constants.EsIndexOperateRecord)
	for _, record := range docList {
		doc := elastic.NewBulkIndexRequest().Doc(record)
		fmt.Println("doc: ", utils.EchoJson(doc))
		req.Add(doc)
	}
	if req.NumberOfActions() < 0 {
		logx.WithContext(r.ctx).Infof("no Operate Record synced to Elasticsearch:%+v", docList)
		return nil
	}
	if _, err := req.Do(r.ctx); err != nil {
		logx.WithContext(r.ctx).Infof("Operate Record synced to Elasticsearch:%+v", docList)
		return err
	}

	return nil
}

type EsSearchOperateRecordParams struct {
	OperateRecordESDocument
	CreateStartTime string `json:"create_start_time"`
	CreateEndTime   string `json:"create_end_time"`
	Keyword         string `json:"keyword"`
	Page            int    `json:"page"`
	PageSize        int    `json:"page_size"`
}

// SelectEsData 从ES中查询数据
func (r *OperateRecordESRepository) SelectEsData(req *EsSearchOperateRecordParams) ([]OperateRecordESDocument, int64, error) {
	boolQuery := elastic.NewBoolQuery()

	// 添加精确匹配条件
	if req.BusinessTypeFirst > 0 {
		boolQuery = boolQuery.Must(elastic.NewTermQuery("business_type_first", req.BusinessTypeFirst))
	}
	if req.BusinessTypeSecond > 0 {
		boolQuery = boolQuery.Must(elastic.NewTermQuery("business_type_second", req.BusinessTypeSecond))
	}
	if req.OperateTable != "" {
		boolQuery = boolQuery.Must(elastic.NewTermQuery("operate_table", req.OperateTable))
	}
	if req.OperateTableId > 0 {
		boolQuery = boolQuery.Must(elastic.NewTermQuery("operate_table_id", req.OperateTableId))
	}
	if req.OperateType > 0 {
		boolQuery = boolQuery.Must(elastic.NewTermQuery("operate_type", req.OperateType))
	}
	if req.CreateStaffId > 0 {
		boolQuery = boolQuery.Must(elastic.NewTermQuery("create_staff_id", req.CreateStaffId))
	}

	// 添加模糊搜索条件
	if req.Keyword != "" {
		boolQuery = boolQuery.Must(elastic.NewMatchQuery("before_data", req.Keyword))
		boolQuery = boolQuery.Must(elastic.NewMatchQuery("after_data", req.Keyword))
	}

	// 添加时间范围搜索条件
	if req.CreateStartTime != "" && req.CreateEndTime != "" {
		loc, _ := time.LoadLocation("Asia/Shanghai")
		// 将字符串格式的时间转换为时间戳
		startTime, err := time.ParseInLocation("2006-01-02 15:04:05", req.CreateStartTime, loc)
		if err != nil {
			logx.WithContext(r.ctx).Errorf("Failed to parse start time: %v", err)
			return nil, 0, err
		}
		endTime, err := time.ParseInLocation("2006-01-02 15:04:05", req.CreateEndTime, loc)
		if err != nil {
			logx.WithContext(r.ctx).Errorf("Failed to parse end time: %v", err)
			return nil, 0, err
		}
		// 使用时间戳进行范围查询
		boolQuery = boolQuery.Must(elastic.NewRangeQuery("create_time").Gte(startTime.Unix()).Lte(endTime.Unix()))
	}

	// 构建搜索请求
	searchResult, err := r.esClient.Search().
		Index(es_constants.EsIndexOperateRecord).
		Query(boolQuery).
		From((req.Page-1)*req.PageSize).
		Size(req.PageSize).
		Sort("create_time", false). // true-正序，false-倒序
		Sort("id", false).          // 根据 id 倒序排序: true-正序，false-倒序
		Do(r.ctx)
	if err != nil {
		logx.WithContext(r.ctx).Errorf("Failed to search Elasticsearch: %v", err)
		return nil, 0, err
	}

	operateRecordList := make([]OperateRecordESDocument, 0)
	for _, hit := range searchResult.Hits.Hits {
		var operateRecord OperateRecordESDocument
		// 使用 json.Unmarshal 手动解析 Elasticsearch 返回的 JSON 数据
		//fmt.Println("hit.Source: ", utils.EchoJson(hit.Source))
		err := json.Unmarshal(hit.Source, &operateRecord)
		//fmt.Println("operateRecord: ", utils.EchoJson(operateRecord))
		if err != nil {
			logx.WithContext(r.ctx).Errorf("Failed to unmarshal hit to operateRecord: %v, Hit: %s", err, hit.Source)
			continue
		}
		operateRecordList = append(operateRecordList, operateRecord)
	}

	if len(operateRecordList) == 0 {
		logx.WithContext(r.ctx).Infof("No items converted to operateRecord, total hits: %d", searchResult.TotalHits())
	}
	return operateRecordList, searchResult.TotalHits(), nil
}

/*
func (r *OperateRecordESRepository) DeleteEsData() error {
	// 删除索引
	_, err := r.esClient.DeleteIndex(es_constants.EsIndexOperateRecord).Do(r.ctx)
	if err != nil {
		return err
	}
	return nil
}
*/
